using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Text;
using OpenComposite.Base.Designer;
using OpenComposite.EII.Repository;

namespace OpenComposite.EII.Designer.BUSView
{
	public class BUSSymbol : DesignerControl, IConnector, IConnectorFactory
	{
		#region Initialization
		public BUSSymbol()
		{
			init();
		}
		private void init()
		{
			this.BeginUpdate();

			_inputDoc = null;
			//_outputDoc = null;

			_path = new GraphicsPath();
			_pathCap = new GraphicsPath();
			_colorBack = Color.DeepSkyBlue;
			_lstActivities = new List<BUSActivitySymbol>();

			//
			// _penStart
			//
			_penStart = new Pen(Color.DarkBlue, 1);
			_penStart.StartCap = LineCap.RoundAnchor;
			_penStart.EndCap = LineCap.Custom;
			_penStart.CustomEndCap = new AdjustableArrowCap(5.0f, 5.0f, true);
			//
			// _inputDoc
			//
			_inputDoc = new BUSDocumentSymbol();
			_inputDoc.ContextMenuStrip.Items.Clear();
			_inputDoc.Location = new Point(0, 20);
			_inputDoc.IsPublishedDocument = true;
			_inputDoc.BusinessObjectsListChanged += new EventHandler(_inputDoc_BusinessObjectsListChanged);
			this.Controls.Add(_inputDoc);

			this.Bounds = new Rectangle(0, 0, 500, 70);
			this.MinimumSize = new Size(300, 70);

			this.ContextMenuStrip.Items.Clear();
			this.ContextMenuStrip.Items.Add("Rule Vocabulary Assignment...", null,
				new EventHandler(this.VocabularyResolve_Click));

			this.EndUpdate();
		}

		private void _inputDoc_BusinessObjectsListChanged(object sender, EventArgs e)
		{
			_inputDoc.Location = new Point(0, /*this.Top +-*/ 20 - _inputDoc.Height);
		}
		#endregion

		#region Public Members

		#region Properties
		// new
		public List<BUSActivitySymbol> Activities
		{
			get { return _lstActivities; }
		}
		public int ActivitiesMinX
		{
			get { return cBUSStartX + 50; }
		}
		public NamedBusinessObjectCollection InputBusinessObjects
		{
			get
			{
				return _inputDoc.NamedBusinessObjects;
			}
		}
		//public Repository.BusinessObject OutputBusinessObject
		//{
		//    get
		//    {
		//        if ( _outputDoc != null && _outputDoc.NamedBusinessObjects.Count > 0 )
		//            return _outputDoc.NamedBusinessObjects[0].BusinessObject;
		//        else
		//            return null;
		//    }
		//    set
		//    {
		//        if ( _outputDoc == null ) {
		//            _outputDoc = new BUSDocumentSymbol();
		//            _outputDoc.ContextMenuStrip.Items.Clear();
		//            _outputDoc.Location = new Point(this.Left + 40, this.Top + 50);
		//            this.DesignerViewControl.DesignerControls.Add(_outputDoc);
		//        } else {
		//            _outputDoc.NamedBusinessObjects.Clear();
		//        }
		//        if ( value != null )
		//            _outputDoc.NamedBusinessObjects.Add(value.Name, value, null);
		//    }
		//}
		private bool _hasOutput;
		public bool HasOutput
		{
			get { return _hasOutput; }
			set { _hasOutput = value; }
		}

		// override
		public override bool CanFocused
		{
			get
			{
				return true;
			}
		}
		public override bool CanMove
		{
			get
			{
				return false;
			}
		}
		public override bool CanResize
		{
			get
			{
				return true;
			}
		}
		public override ResizeSides ResizableSides
		{
			get
			{
				return ResizeSides.Right;
			}
		}
		public override bool CanSelect
		{
			get
			{
				return true;
			}
		}

		public override bool CanDrag
		{
			get
			{
				return false;
			}
		}

		public override Color BackColor
		{
			get
			{
				return _colorBack;
			}
			set
			{
				if ( _colorBack != value ) {
					_colorBack = value;
					buildBrushes();
				}
			}
		}
		public override bool UseGrid
		{
			get
			{
				return true;
			}
		}
		#endregion

		#region Methods
		// new

		// override
		public override void PaintBackground(System.Windows.Forms.PaintEventArgs pe)
		{
			pe.Graphics.SmoothingMode = SmoothingMode.AntiAlias;

			// draw bus
			pe.Graphics.DrawPath(Pens.DarkBlue, _path);
			pe.Graphics.FillPath(_brushGradient, _path);

			pe.Graphics.DrawPath(Pens.DarkBlue, _pathCap);
			pe.Graphics.FillPath(_brushCap, _pathCap);

			// draw workflow start
			Rectangle r = this.GetPaintBounds();
			Rectangle rstart = new Rectangle(r.Left, r.Top + 20, 30, 30);
			pe.Graphics.DrawEllipse(Pens.Blue, rstart);
			using ( LinearGradientBrush brush = new LinearGradientBrush(rstart, Color.White, Color.CornflowerBlue, LinearGradientMode.ForwardDiagonal) ) {
				pe.Graphics.FillEllipse(brush, rstart);
			}

			bool hasInput = ( this._inputDoc != null && this._inputDoc.NamedBusinessObjects.Count > 0 );

			if ( !this.HasOutput ) {
				pe.Graphics.DrawLine(_penStart, new Point(50, this.Top + (int)( this.Height * .5 )), new Point(this.Left + cBUSStartX + 15, this.Top + (int)( this.Height * .5 )));
			} else {
				pe.Graphics.DrawLine(_penStart, new Point(45, this.Top + 25), new Point(this.Left + cBUSStartX + 15, this.Top + 25));
			}

			//if ( hasOutput ) {
			//    pe.Graphics.DrawLine(_penStart, new Point(this.Left + cBUSStartX + 15, this.Top + 45), new Point(45, this.Top + 45));
			//}
			pe.Graphics.Flush();
		}
		public override void Paint(System.Windows.Forms.PaintEventArgs pe)
		{
			base.Paint(pe);
		}
		#endregion

		#endregion

		#region Protected Members

		#region Properties
		protected override Brush BackBrush
		{
			get
			{
				return _brushGradient;
			}
		}
		#endregion

		#region Methods
		// new

		// override
		protected override void OnSizeChanged(EventArgs e)
		{
			buildPath();
			buildBrushes();
			base.OnSizeChanged(e);
		}
		protected override void OnLocationChanged(EventArgs e)
		{
			buildPath();
			buildBrushes();
			base.OnLocationChanged(e);
		}

		public override bool IsDropAllowed(object obj, Point location, System.Windows.Forms.MouseButtons button)
		{
			if ( obj == null )
				return false;
			else
				return this.IsDropAllowed(obj.GetType(), location, button);
		}
		public override bool IsDropAllowed(Type type, Point location, System.Windows.Forms.MouseButtons button)
		{
			return ( type == typeof(BUSActivitySymbol) );
		}
		public override void DropObject(object obj, Point location, System.Windows.Forms.MouseButtons button)
		{
			BUSActivitySymbol busact = obj as BUSActivitySymbol;
			if ( busact != null ) {
				this.Activities.Add(busact);
				Route route = this.DesignerViewControl.AddRoute(busact, this);
				route.Removed += new EventHandler(route_Removed);
			}
		}

		public void route_Removed(object sender, EventArgs e)
		{
			Route route = sender as Route;
			if ( route != null ) {
				route.Removed -= new EventHandler(route_Removed);
			}
		}
		public override object GetDragObject(Point location, System.Windows.Forms.MouseButtons button)
		{
			return null;
		}


		#endregion

		#endregion

		#region Private Members

		#region Constants
		private const int cBUSStartX = 120;
		#endregion

		#region Variables

		BUSDocumentSymbol _inputDoc;
		//BUSDocumentSymbol _outputDoc;

		Color _colorBack;

		GraphicsPath _path;
		GraphicsPath _pathCap;

		Pen _penStart;

		LinearGradientBrush _brushGradient;
		LinearGradientBrush _brushCap;

		List<BUSActivitySymbol> _lstActivities;
		#endregion

		#region Methods

		private void buildPath()
		{
			int h2 = this.Height / 2;

			_path.Reset();
			//_path.AddRectangle(this.Bounds);
			_path.AddArc(this.Location.X + cBUSStartX, this.Location.Y,
						 h2, this.Size.Height, 270, -180);
			_path.AddArc(this.Location.X + this.Size.Width - h2, this.Location.Y,
						 h2, this.Size.Height, 90, -180);
			_path.CloseFigure();

			_pathCap.Reset();
			_pathCap.AddEllipse(this.Location.X + cBUSStartX, this.Location.Y, h2, this.Size.Height);
		}
		private void buildBrushes()
		{
			dispose(_brushGradient);
			dispose(_brushCap);

			_brushGradient = new LinearGradientBrush(this.Bounds,
				Color.DodgerBlue, Color.White, LinearGradientMode.Vertical);
			_brushGradient.SetSigmaBellShape(0.25f);

			_brushCap = new LinearGradientBrush(this.Bounds,
				Color.RoyalBlue, Color.White, LinearGradientMode.Vertical);
			_brushCap.SetSigmaBellShape(0.75f, 0.75f);
		}

		#endregion

		#region Event Handler

		private void VocabularyResolve_Click(object sender, EventArgs e)
		{
			BUSViewController view = this.DesignerViewControl.DesignController as BUSViewController;
			Debug.Assert(view != null);
			FormVocabularyResolve frm = new FormVocabularyResolve(view.Workflow, view);
			frm.ShowDialog();
		}

		#endregion

		#endregion

		#region IConnector Members

		public Point GetRouteEnd(RouteDockDirection dock, Route route)
		{
			// document published
			Rectangle r = this.GetPaintBounds();
			if ( dock == RouteDockDirection.Top )
				return new Point(0, r.Top);
			else if ( dock == RouteDockDirection.Bottom )
				return new Point(0, r.Bottom);
			else
				return Point.Empty;
		}

		public Point GetRouteStart(RouteDockDirection dock, Route route)
		{
			BUSActivitySymbol bas = route.EndControl as BUSActivitySymbol;
			if ( bas != null && bas.IsProcessReply ) {
				return new Point(this.Location.X + 130, this.Location.Y + 45);
			} else {
				// document subscribed
				Rectangle r = this.GetPaintBounds();
				if ( dock == RouteDockDirection.Top )
					return new Point(0, r.Top);
				else if ( dock == RouteDockDirection.Bottom )
					return new Point(0, r.Bottom);
				else
					return Point.Empty;
			}
		}

		#endregion

		#region IConnectorFactory Members

		public bool CreateRouteEnd(DesignerControl controlStart,
			out IConnector connector, out LineCap cap, out CustomLineCap customcap,
			out RouteDockDirection dockStart, out RouteDockDirection dockEnd,
			out bool useEndConnectorAsRouteEnd)
		{
			// document published
			bool ok = false;

			cap = LineCap.Custom;
			customcap = new AdjustableArrowCap(5.0f, 5.0f, true);
			useEndConnectorAsRouteEnd = true;
			connector = this;

			BUSActivitySymbol busact = controlStart as BUSActivitySymbol;
			if ( busact != null ) {
				if ( controlStart.Bottom < this.Top ) {
					dockStart = RouteDockDirection.Bottom;
					dockEnd = RouteDockDirection.Top;
				} else {
					dockStart = RouteDockDirection.Top;
					dockEnd = RouteDockDirection.Bottom;
				}
				ok = true;
			} else {
				dockStart = RouteDockDirection.Bottom;
				dockEnd = RouteDockDirection.Top;
			}
			return ok;
		}

		public bool CreateRouteStart(DesignerControl controlEnd,
			out IConnector connector, out LineCap cap, out CustomLineCap customcap,
			out RouteDockDirection dockStart, out RouteDockDirection dockEnd,
			out bool useStartConnectorAsRouteStart)
		{
			// document subscribed
			bool ok = false;

			cap = LineCap.RoundAnchor;
			customcap = null;
			useStartConnectorAsRouteStart = true;
			connector = this;

			BUSActivitySymbol busact = controlEnd as BUSActivitySymbol;
			if ( busact != null ) {
				if ( controlEnd.Bottom > this.Top ) {
					dockStart = busact.IsProcessReply ? RouteDockDirection.Left : RouteDockDirection.Bottom;
					dockEnd = busact.IsProcessReply ? RouteDockDirection.Right : RouteDockDirection.Top;
				} else {
					dockStart = busact.IsProcessReply ? RouteDockDirection.Right : RouteDockDirection.Top;
					dockEnd = busact.IsProcessReply ? RouteDockDirection.Left : RouteDockDirection.Bottom;
				}
				ok = true;
			} else {
				dockStart = busact.IsProcessReply ? RouteDockDirection.Left : RouteDockDirection.Bottom;
				dockEnd = busact.IsProcessReply ? RouteDockDirection.Right : RouteDockDirection.Top;
			}
			return ok;
		}

		#endregion
	}
}
